// $codepro.audit.disable unnecessaryOverride, overloadedMethods
/**
 * Nurse.java
 * @author Peter
 */
// $codepro.audit.disable booleanMethodNamingConvention
package edu.gatech.coc.betameisters.people;

import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import edu.gatech.coc.betameisters.infoholders.Invoice;
import edu.gatech.coc.betameisters.infoholders.Constants.UserType;
import edu.gatech.coc.betameisters.userinterfaces.InvoiceView;
import edu.gatech.coc.betameisters.utilities.Database;

/**
 * The Nurse class; this represents the nurses in our system
 * 
 * @author Peter
 * 
 * @version $Revision: 1.0 $
 */
public class Nurse extends Person {
	/**
	 * 
	 */
	private static final long serialVersionUID = 557585163526527034L;

	/**
	 * The nurse's current patient
	 */
	protected Patient currentPatient;
	
	// will need to access DB here for patient list, synchronizing needed as
	// well
	/**
	 * Field patientDB.
	 */
	protected Map<String, Patient> patientDB;

	// for searching the patient real name
	/**
	 * Field patientNameDB Holds patients real names and maps to respected
	 * username Real name formated: last name space first name
	 */
	protected Map<String, List<String>> patientNameDB;

	/**
	 * Constructor that creates nurses and adds the nurse to the database
	 * 
	 * @param fName
	 * @param lName
	 */
	public Nurse(final String fName, final String lName) { // $codepro.audit.disable
															// com.instantiations.assist.eclipse.analysis.audit.rule.effectivejava.constructorsOnlyInvokeFinalMethods
		super(fName, lName);
		patientDB = new HashMap<String, Patient>();
		patientNameDB = new HashMap<String, List<String>>();
		MYLOGGER.info("In Nurse constructor");
		personType = UserType.NURSE;
//		createPatient("Peter", "D"); // $codepro.audit.disable
//										// com.instantiations.assist.eclipse.analysis.unusedReturnValue
//		createPatient("Suren", "N"); // $codepro.audit.disable
//										// com.instantiations.assist.eclipse.analysis.unusedReturnValue
//		createPatient("William", "H"); // $codepro.audit.disable
//										// com.instantiations.assist.eclipse.analysis.unusedReturnValue
//		createPatient("Henry", "S"); // $codepro.audit.disable
//										// com.instantiations.assist.eclipse.analysis.unusedReturnValue
//		// store the object to the database
	}

	/**
	 * Constructor for a nurse that does not save to the database
	 * @param username Username
	 * @param password Password
	 * @param fName First name
	 * @param lName Last name
	 * @param patient patient object
	 */
	public Nurse(final String username, final String password, final String fName,  // $codepro.audit.disable com.instantiations.assist.eclipse.analysis.audit.rule.effectivejava.constructorsOnlyInvokeFinalMethods
			final String lName, final Patient patient) {
		super(username, password, fName, lName);
		MYLOGGER.info("In Nurse constructor");
		personType = UserType.NURSE;
		this.setCurrentPatient(patient);
	}

	/**
	 * Generic constructor for a Nurse for database use
	 */
	public Nurse() {
		super(); // $codepro.audit.disable invocationOfDefaultConstructor
		personType = UserType.NURSE;
		MYLOGGER.info("In Nurse constructor");
	}

	/**
	 * Getter for the current patient
	 * 
	 * @return the username of the nurse's current patient
	 */
	public Patient getCurrentPatient() {
		// handle null patient
		if(currentPatient == null) {
			System.err.println("This nurse's current patient does not exist");
			return null;
		}
		// otherwise retrieve patient
		final String checkPatient = "SELECT * FROM patient WHERE `username`='" +
			currentPatient.getUserID() + "'";
		if(Database.checkExistence(checkPatient)) {
			return currentPatient;
		}
		else {
			this.setCurrentPatient(null);
			return null;
		}
		
	}

	/**
	 * Setter for the username of the current patient
	 * 
	 * @param currentPatient the new patient
	 */
	public void setCurrentPatient(Patient currentPatient) {
		// handle the case of a null patient
		String patID = "";
		if(currentPatient != null) {
			patID = currentPatient.getUserID();
		}
		// set the username in the database first String currentPatientUpdate
		final String cPatientUpdate = "UPDATE " + this.getClass().getSimpleName() + " " +
			"SET `patient` = '" + patID + "' " + 
			"WHERE `username` = '" + this.getUserID() + "'";
		
		// only try to update the patient if the operation was successful
		if(Database.executeUpdateQuery(cPatientUpdate)) {
			this.currentPatient = currentPatient;
		}
	}

	/**
	 * Creates a patient object
	 * 
	 * @param fName
	 *            - first name of patient
	 * @param lName
	 *            - last name of patient
	 * 
	 * @return a boolean that the patient is successfully created and stored
	 */
	public Patient createPatient(String fName, String lName) {
		MYLOGGER.info(this.getClass().getSimpleName() + " is trying to add patient");
		final Patient someone = new Patient(fName, lName);
		MYLOGGER.info("User " + this.getUserID() + " has created user " + someone);
		return someone;
	}

	/**
	 * Delete's a patient given their object
	 * @param pat Patient object
	 * @return true if successful, false otherwise
	 */
	public boolean deletePatient(Patient pat) {
		return pat.delete();
	}
	
	/**
	 * Delete's a patient based on their username
	 * @param patientUsername username of the patient
	 * @return true if successful, false otherwise
	 */
	public boolean deletePatient(String patientUsername) {
		final Patient pat = Database.loadPatient(patientUsername); 
		if(pat != null) {
			MYLOGGER.info("Patient deleted from system");
			return pat.delete();
		}
		else {
			MYLOGGER.warning("Patient not found in system, abort deletion");
			return false;
		}
	}

	/**
	 * Will search for the patient and service that patient
	 * 
	 * @param uName
	 *            - patient's username or real name
	 * @param isUserName
	 * 
	 * @return a list of patients (in case there were multiple people with same
	 *         name)
	 */
	public List<String> searchPatient(String uName, boolean isUserName) { 
		final List<String> userNameHit = new LinkedList<String>(); 
		MYLOGGER.info("Nurse/Doctor is trying to search for patient in system");
		if (!isUserName) {
			final char[] split = uName.toCharArray();
			String fName = "", lName = "";
			for(int i = 0; i < uName.length(); i++){
				if(Character.toString(split[i]).equals(" ")){
					fName = lName;
					lName = "";
				}
				else{
					lName += split[i]; // $codepro.audit.disable stringConcatenationInLoop
				}
			}
			System.out.println(fName + lName);
			final List<Patient> patientList = Database.searchPatientByName(fName, lName);
			
			if (patientList.isEmpty()) {
				MYLOGGER.info("Patient not found in system");
				return new LinkedList<String>();
			} else {
				MYLOGGER.info("Patient(s) found in system");
				Patient temp;
				while(!patientList.isEmpty()){
					temp = patientList.remove(0);
					userNameHit.add(temp.getUserID());
				}
				return userNameHit;
			}
		} else {
			// search and set equal to current
			final List<Patient> patientList = Database.searchPatient(uName);
			if(!patientList.isEmpty()){
				currentPatient = patientList.get(0);
				userNameHit.add(uName);
				MYLOGGER.info("Patient found in system");
				return userNameHit;
			}
			else{
			MYLOGGER.warning("Patient not found in system");
			return new LinkedList<String>();
			}
		}
	}

	/**
	 * Ideally a UI button, pulls up a section that will allow the nurse to edit
	 * patient details
	 */
	public void modifyPatient() {
		MYLOGGER.info("Nurse/Doctor is trying to modify current patient details");
	}

	/**
	 * Ideally a UI button, pulls up a section that will allow the nurse to see
	 * a list of appointments for the day/week
	 */
	public void viewAppointments() {
		MYLOGGER.info("Nurse/Doctor is viewing appointment page");
		// pulls up appointment page on UI
	}

	/**
	 * Create an appointment with the current user
	 * @param month Month
	 * @param day Day
	 * @param year Year
	 * @param sHour Start Hour
	 * @param sMinute Start Minute
	 * @param eHour End Hour
	 * @param eMinute End Minute 
	 * @param descrpt Description
	 * @return true if successful, false otherwise
	 */
	public boolean createAppointment(int month, int day, int year, // $codepro.audit.disable largeNumberOfParameters
			int sHour, int sMinute, int eHour, int eMinute, String descrpt) {
		MYLOGGER.info("Nurse/Doctor is trying to create an appointment");
		return true;
	}

	/**
	 * Ideally a UI button, pulls up a section that will allow the nurse to
	 * create a treatment for the patient
	 * 
	 * 
	 * @return a boolean where true signals that a treatment has been created
	 *         and false signals that it was not created
	 */
	public boolean createTreatment() {
		MYLOGGER.info("Nurse/Doctor is trying to create a new treatment for patient");
		// pulls up UI for treatment details for current patient
		return true;
	}

	/**
	 * Overrides the default toString method
	 * 
	 * @return Nurse's name
	 */
	public String toString() {
		return "Nurse: " + this.getFirstName() + " " + this.getLastName();
	}

	/**
	 * Ideally a UI button, a button when pressed that bills the patient
	 */
	public void billPatient() {
		MYLOGGER.info("Nurse/Doctor is trying to bill patient");
		final PrinterJob printJob = PrinterJob.getPrinterJob();
		final Invoice myI = new Invoice("");

		final InvoiceView v = new InvoiceView(myI, null);
		printJob.setPrintable(v);
		if (printJob.printDialog()) { // $codepro.audit.disable
										// nullPointerDereference
			try {
				printJob.print();
			} catch (PrinterException pe) {
				System.out.println("Error printing: " + pe);
			}
		}
	}

	/**
	 * // $codepro.audit.disable unnecessaryOverride Adds this Nurse object into
	 * the database
	 */
	public void create() {
		super.create();
	}
}
